package com.littlerpc.registry.zookeeper;

import lombok.Getter;
import org.apache.zookeeper.*;

import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static com.littlerpc.registry.zookeeper.ZookeeperConfig.ROOT_NODE;
import static com.littlerpc.registry.zookeeper.ZookeeperConfig.SERVER_NODE;


/**
 * Created by ChengPeng on 2017/7/5.
 */
public class ZookeeperRegistry implements Closeable {

    private CountDownLatch latch = new CountDownLatch(1);
    @Getter
    private volatile boolean isConnected = false;

    private ZooKeeper zk = null;

    /**
     * 构造方法，初始化zookeeper链接
     */
    public ZookeeperRegistry(ZookeeperConfig zkConf) {
        String connectString = zkConf.getConnectString();
        int timeout = zkConf.getTimeout();

        try {
            zk = new ZooKeeper(connectString, timeout, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (event.getState() == Event.KeeperState.SyncConnected) {
                        latch.countDown();
                    }
                }
            });
            //等待链接完成
            latch.await(5, TimeUnit.SECONDS);
            isConnected = true;
            //创建server注册的根节点
            createRootNode();
        } catch (Exception e) {
            //ignore
        }
    }

    /**
     * 想zk注册节点数据
     */
    public void register(String nodeData) {
        ZookeeperUtils.createNode(zk, SERVER_NODE + "_" + nodeData, nodeData, CreateMode.EPHEMERAL);
    }


    /**
     * 添加根节点，
     * 用于server注册 根节点，是需要持久存在的。
     * OPEN_ACL_UNSAFE     是所有ACL都“开放”了：任何应用程序在节点上可进行任何操作，能创建、列出和删除它的子节点。对任何应用程序，
     * ZOO_READ_ACL_UNSAFE 是只读的。
     * CREATE_ALL_ACL  赋予了节点的创建者所有的权限，
     * 在创建者采用此ACL创建节点之前，已经被服务器所认证（例如，采用“ digest”方案）。
     */
    private void createRootNode() {
        ZookeeperUtils.createNode(zk, ROOT_NODE, null, CreateMode.PERSISTENT);
    }

    @Override
    public void close() throws IOException {
        if (zk != null) {
            try {
                zk.close();
            } catch (InterruptedException e) {
                //ignore
            }
        }
    }
}
